package com.mju.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alipay.api.internal.util.AlipaySignature;
import com.mju.config.AlipayClientConfig;
import com.mju.controller.common.BaseController;
import com.mju.controller.common.JsonResult;
import com.mju.feign.clients.OrderClient;
import com.mju.feign.clients.VipClient;
import com.mju.pojo.Order;
import com.mju.pojo.Receive;
import com.mju.pojo.vo.OrderVo;
import com.mju.service.IAliPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

// 处理支付宝沙箱支付的接口
@Slf4j
@RestController
@RequestMapping("/alipay")
@Api(tags = "支付宝沙箱支付")
public class AliPayController extends BaseController {
  @Autowired private IAliPayService aliPayService;
  @Autowired private OrderClient orderClient;
  @Autowired private VipClient vipClient;

  // 处理购物车里商品在线支付的请求
  @ApiOperation("购物车商品在线支付")
  @GetMapping(value = "/pay", produces = "text/html;charset=UTF-8")
  public String goAlipay(
          @RequestParam("aid") Integer aid,
          @RequestParam("cids") Integer[] cids,
          @RequestParam("token") String token) {
    String uid = parseTokenGetUid(token);
    JsonResult<Order> data = orderClient.createOrderByToken(aid, cids, token);
    Order order = data.getData();
    return aliPayService.createPay(order, uid);
  }

  // 处理待支付里商品在线支付的请求
  @ApiOperation("待支付里商品在线支付")
  @GetMapping(value = "/waitForPay", produces = "text/html;charset=UTF-8")
  public String waitForPay(@RequestParam("oid") Integer oid, @RequestParam("token") String token) {

    int uid = Integer.parseInt(parseTokenGetUid(token));

    // 根据oid查询未支付的订单
    JsonResult<List<OrderVo>> data = orderClient.queryOrderByOid(oid);
    List<OrderVo> orderVos = data.getData();
    if (Objects.isNull(orderVos)) {
      log.error("未查询到未支付订单...");
      return null;
    }
    Order order = new Order();
    order.setOid(orderVos.get(0).getOid());
    order.setTotalPrice(orderVos.get(0).getTotalPrice());

    return aliPayService.createPay(order, String.valueOf(uid));
  }

  // 二手回收打款
  @ApiOperation("二手回收打款")
  @PostMapping("/transferAccounts")
  public JsonResult transferAccounts(
          @RequestParam("accountNumber") String accountNumber,
          @RequestParam("payeeName") String payeeName,
          @RequestBody Receive receive) {
    String message = aliPayService.transferAccounts(accountNumber, payeeName, receive);
    return new JsonResult(OK, message);
  }

  // 处理购买会员在线支付的请求
  @ApiOperation("购买会员在线支付")
  @GetMapping(value = "/buyVip/{vipName}/{day}/{amount}", produces = "text/html;charset=UTF-8")
  public String buyVip(
          @PathVariable String vipName,
          @PathVariable Integer day,
          @PathVariable Integer amount,
          @RequestParam(value = "token") String token) {

    // 获取uid
    String uid = parseTokenGetUid(token);

    return aliPayService.buyVip(vipName, uid, day, amount);
  }

  // 购买VIP处理异步回调
  @ApiOperation("购买会员的异步回调")
  @PostMapping("/notifyUrlForVip")
  public String notifyNoticeForVip(
          @RequestParam Map<String, String> params, HttpServletRequest request) throws Exception {

    log.info("支付成功, 进入异步通知接口...");
    log.info("通知参数" + params);

    String result = "failure";

    // 调用SDK验证签名
    boolean signVerified =
            AlipaySignature.rsaCheckV1(
                    params,
                    AlipayClientConfig.alipayPublicKey,
                    AlipayClientConfig.charset,
                    AlipayClientConfig.signType);

    if (!signVerified) {
      // 验签失败
      log.error("支付成功异步通知验签失败...");
      return result;
    } else {
      // 验签成功
      log.info("支付成功异步通知验签成功...");

      // 订单号
      String out_trade_no = params.get("out_trade_no");

      // 付款金额
      String total_amount = params.get("total_amount");
      int totalAmount = new BigDecimal(total_amount).intValue();

      // 商家的sellerId
      String seller_id = params.get("seller_id");
      // 校验商家的sellerId
      if (!AlipayClientConfig.sellerId.equals(seller_id)) {
        log.error("商家id校验失败...");
        return result;
      }

      // app_id
      String app_id = params.get("app_id");
      // 校验app_id是否商家本身
      if (!AlipayClientConfig.appId.equals(app_id)) {
        log.error("appid校验失败...");
        return result;
      }

      // 获取在支付接口中保存的uid
      String passback_params = params.get("passback_params");

      // 对传回的数据进行编码的逆过程，对参数进行解码
      String paramsStr = URLDecoder.decode(passback_params, "UTF-8");

      Map<String, String> map =
              JSON.parseObject(paramsStr, new TypeReference<HashMap<String, String>>() {});
      Integer uid = Integer.parseInt(map.get("uid"));

      // 支付宝交易号
      String trade_no = params.get("trade_no");

      // 交易状态
      String trade_status = params.get("trade_status");

      if (trade_status.equals("TRADE_SUCCESS")) {
        // 支付成功
        result = "success";

        // 处理开通VIP
        aliPayService.processVip(params);

        log.info("********************** 购买会员成功(支付宝异步通知) **********************");
        log.info("* 当前支付用户的id: {}", uid);
        log.info("* 订单号: {}", out_trade_no);
        log.info("* 支付宝交易号: {}", trade_no);
        log.info("* 实付金额: {}", total_amount);
        log.info("***************************************************************");
      }
    }
    return result;
  }

  // 购买会员同步回调方法
  @ApiOperation("购买会员的同步回调")
  @GetMapping("/returnNoticeForVip")
  public JsonResult alipayReturnNoticeForVip(
          @RequestParam Map<String, String> params,
          HttpServletRequest request,
          HttpServletResponse response)
          throws Exception {

    log.info("支付成功, 进入同步通知接口...");
    log.info("通知参数" + params);

    // 调用SDK验证签名
    boolean signVerified =
            AlipaySignature.rsaCheckV1(
                    params,
                    AlipayClientConfig.alipayPublicKey,
                    AlipayClientConfig.charset,
                    AlipayClientConfig.signType);
    // 获取信息
    if (!signVerified) {
      // 验签失败
      log.error("支付成功支付宝同步通知验签失败...");
    } else {
      // 验签成功
      log.info("支付成功支付宝同步通知验签成功...");

      // 订单号
      String out_trade_no = params.get("out_trade_no");
      // 支付宝交易号
      String trade_no = params.get("trade_no");
      // 付款金额
      String total_amount = params.get("total_amount");

      // 重定向到购买成功页面
      //      response.sendRedirect("http://localhost:8090/payment?oid="+out_trade_no);
      response.sendRedirect("http://localhost:8090/");

      log.info("********************** 购买会员成功(支付宝同步通知) **********************");
      log.info("* 订单号: {}", out_trade_no);
      log.info("* 支付宝交易号: {}", trade_no);
      log.info("* 实付金额: {}", total_amount);
      log.info("***************************************************************");
    }
    return new JsonResult(OK, "支付成功");
  }

  // 处理订单异步回调
  @ApiOperation("在线支付订单的异步回调")
  @PostMapping("/notifyNotice")
  public String alipayNotifyNotice(
          @RequestParam Map<String, String> params, HttpServletRequest request) throws Exception {

    log.info("支付成功, 进入异步通知接口...");
    log.info("通知参数" + params);

    String result = "failure";

    // 调用SDK验证签名
    boolean signVerified =
            AlipaySignature.rsaCheckV1(
                    params,
                    AlipayClientConfig.alipayPublicKey,
                    AlipayClientConfig.charset,
                    AlipayClientConfig.signType);

    if (!signVerified) {
      // 验签失败
      log.error("支付成功异步通知验签失败...");
      return result;
    } else {
      // 验签成功
      log.info("支付成功异步通知验签成功...");

      // 订单号
      String out_trade_no = params.get("out_trade_no");

      JsonResult<List<OrderVo>> data = orderClient.queryOrderByOid(Integer.valueOf(out_trade_no));
      List<OrderVo> orderVos = data.getData();
      if (orderVos == null) {
        log.error("订单不存在...");
        return result;
      }
      // 付款金额
      String total_amount = params.get("total_amount");
      double totalAmount = new BigDecimal(total_amount).doubleValue();
      // 校验付款金额
      double totalPrice = new BigDecimal(orderVos.get(0).getTotalPrice()).doubleValue();
      if (!(totalAmount == totalPrice)) {
        log.error("付款金额校验失败...");
        return result;
      }

      // 商家的sellerId
      String seller_id = params.get("seller_id");
      // 校验商家的sellerId
      if (!AlipayClientConfig.sellerId.equals(seller_id)) {
        log.error("商家id校验失败...");
        return result;
      }

      // app_id
      String app_id = params.get("app_id");
      // 校验app_id是否商家本身
      if (!AlipayClientConfig.appId.equals(app_id)) {
        log.error("appid校验失败...");
        return result;
      }
      // 获取在支付接口中保存的uid
      String passback_params = params.get("passback_params");

      // 对传回的数据进行编码的逆过程，对参数进行解码
      String uidStr = URLDecoder.decode(passback_params, "UTF-8");

      // 支付宝交易号
      String trade_no = params.get("trade_no");

      // 交易状态
      String trade_status = params.get("trade_status");

      if (trade_status.equals("TRADE_SUCCESS")) {
        // 支付成功
        result = "success";

        // 处理订单
        aliPayService.processOrder(params);

        log.info("********************** 订单支付成功(支付宝异步通知) **********************");
        log.info("* 当前支付用户的id: {}", passback_params);
        log.info("* 订单号: {}", out_trade_no);
        log.info("* 支付宝交易号: {}", trade_no);
        log.info("* 实付金额: {}", total_amount);
        log.info("***************************************************************");
      }
    }
    return result;
  }

  // 订单同步回调方法
  @ApiOperation("在线支付订单的同步回调")
  @GetMapping("/returnNotice")
  public JsonResult alipayReturnNotice(
          @RequestParam Map<String, String> params,
          HttpServletRequest request,
          HttpServletResponse response)
          throws Exception {

    log.info("支付成功, 进入同步通知接口...");
    log.info("通知参数" + params);

    // 调用SDK验证签名
    boolean signVerified =
            AlipaySignature.rsaCheckV1(
                    params,
                    AlipayClientConfig.alipayPublicKey,
                    AlipayClientConfig.charset,
                    AlipayClientConfig.signType);
    // 获取信息
    if (!signVerified) {
      // 验签失败
      log.error("支付成功支付宝同步通知验签失败...");
    } else {
      // 验签成功
      log.info("支付成功支付宝同步通知验签成功...");

      // 订单号
      String out_trade_no = params.get("out_trade_no");
      // 支付宝交易号
      String trade_no = params.get("trade_no");
      // 付款金额
      String total_amount = params.get("total_amount");

      // 重定向到支付成功页面
      response.sendRedirect("http://localhost:8090/payment?oid=" + out_trade_no);

      log.info("********************** 订单支付成功(支付宝同步通知) **********************");
      log.info("* 订单号: {}", out_trade_no);
      log.info("* 支付宝交易号: {}", trade_no);
      log.info("* 实付金额: {}", total_amount);
      log.info("***************************************************************");
    }
    return new JsonResult(OK, "支付成功");
  }

  // 用户取消订单
  @ApiOperation("取消订单")
  @PostMapping("/close")
  public JsonResult cancel(@RequestParam("oid") Integer oid) {
    log.info("取消订单...");
    aliPayService.cancelOrder(oid);
    return new JsonResult(OK, "订单已取消");
  }
  // 用户申请退款
  @ApiOperation("申请退款")
  @PostMapping("/refund")
  public JsonResult<String> refund(
          @RequestParam("oid") Integer oid, @RequestParam("reason") String reason) {
    log.info("申请退款...");
    aliPayService.refundOrder(oid, reason);
    return new JsonResult(OK, "申请退款成功");
  }

  // 对账，下载账单 日期格式需为：yyyy-MM-dd 账单类型 业务账单-trade 或者资金账单-signcustomer
  @ApiOperation("对账 下载账单 ")
  @GetMapping("/bill-downloadurl/{billDate}/{billType}")
  public JsonResult queryBillDownloadUrl(
          @PathVariable("billDate") String billDate, @PathVariable("billType") String billType) {
    String downloadUrl = aliPayService.queryBill(billDate, billType);
    return new JsonResult(OK, downloadUrl);
  }

  // 处理移动端商品在线支付的请求
  @ApiOperation("移动端商品在线支付")
  @GetMapping(value = "/payForMobileTerminal", produces = "text/html;charset=UTF-8")
  public String goAlipayForMobileTerminal(
          @RequestParam("aid") Integer aid,
          @RequestParam("cids") Integer[] cids,
          @RequestParam("token") String token) {

    String uid = parseTokenGetUid(token);

    JsonResult<Order> data = orderClient.createOrderByToken(aid, cids, token);
    Order order = data.getData();
    return aliPayService.createPayForMobileTerminal(order, uid);
  }

  // 处理移动端订单异步回调
  @ApiOperation("移动端支付订单的异步回调")
  @PostMapping("/notifyUrlForMobileTerminal")
  public String alipayNotifyNoticeForMobileTerminal(
          @RequestParam Map<String, String> params, HttpServletRequest request) throws Exception {

    log.info("支付成功, 进入异步通知接口...");
    log.info("通知参数" + params);
    String result = "failure";
    // 调用SDK验证签名
    boolean signVerified =
            AlipaySignature.rsaCheckV1(
                    params,
                    AlipayClientConfig.alipayPublicKey,
                    AlipayClientConfig.charset,
                    AlipayClientConfig.signType);
    if (!signVerified) {
      // 验签失败
      log.error("支付成功异步通知验签失败...");
      return result;
    } else {
      // 验签成功
      log.info("支付成功异步通知验签成功...");

      // 订单号
      String out_trade_no = params.get("out_trade_no");

      JsonResult<List<OrderVo>> data = orderClient.queryOrderByOid(Integer.valueOf(out_trade_no));
      List<OrderVo> orderVos = data.getData();
      if (orderVos == null) {
        log.error("订单不存在...");
        return result;
      }
      // 付款金额
      String total_amount = params.get("total_amount");
      double totalAmount = new BigDecimal(total_amount).doubleValue();
      // 校验付款金额
      double totalPrice = new BigDecimal(orderVos.get(0).getTotalPrice()).doubleValue();
      if (!(totalAmount == totalPrice)) {
        log.error("付款金额校验失败...");
        return result;
      }

      // 商家的sellerId
      String seller_id = params.get("seller_id");
      // 校验商家的sellerId
      if (!AlipayClientConfig.sellerId.equals(seller_id)) {
        log.error("商家id校验失败...");
        return result;
      }

      // app_id
      String app_id = params.get("app_id");
      // 校验app_id是否商家本身
      if (!AlipayClientConfig.appId.equals(app_id)) {
        log.error("appid校验失败...");
        return result;
      }
      // 获取在支付接口中保存的uid
      String passback_params = params.get("passback_params");

      // 对传回的数据进行编码的逆过程，对参数进行解码
      String uidStr = URLDecoder.decode(passback_params, "UTF-8");

      // 支付宝交易号
      String trade_no = params.get("trade_no");

      // 交易状态
      String trade_status = params.get("trade_status");

      if (trade_status.equals("TRADE_SUCCESS")) {
        // 支付成功
        result = "success";

        // 处理订单
        aliPayService.processOrderForMobileTerminal(params);

        log.info("********************** 移动端订单支付成功(支付宝异步通知) **********************");
        log.info("* 当前支付用户的id: {}", passback_params);
        log.info("* 订单号: {}", out_trade_no);
        log.info("* 支付宝交易号: {}", trade_no);
        log.info("* 实付金额: {}", total_amount);
        log.info("***************************************************************");
      }
    }
    return result;
  }

  // 移动端订单同步回调方法
  @ApiOperation("移动端支付订单的同步回调")
  @GetMapping("/returnNoticeForMobileTerminal")
  public JsonResult alipayReturnNoticeForMobileTerminal(
          @RequestParam Map<String, String> params,
          HttpServletRequest request,
          HttpServletResponse response)
          throws Exception {

    log.info("支付成功, 进入同步通知接口...");
    log.info("通知参数" + params);

    // 调用SDK验证签名
    boolean signVerified =
            AlipaySignature.rsaCheckV1(
                    params,
                    AlipayClientConfig.alipayPublicKey,
                    AlipayClientConfig.charset,
                    AlipayClientConfig.signType);
    // 获取信息
    if (!signVerified) {
      // 验签失败
      log.error("支付成功支付宝同步通知验签失败...");
    } else {
      // 验签成功
      log.info("支付成功支付宝同步通知验签成功...");

      // 订单号
      String out_trade_no = params.get("out_trade_no");
      // 支付宝交易号
      String trade_no = params.get("trade_no");
      // 付款金额
      String total_amount = params.get("total_amount");

      // 重定向到移动端购买成功页面
      response.sendRedirect("http://localhost:8092/success");

      log.info("********************** 移动端订单支付成功(支付宝同步通知) **********************");
      log.info("* 订单号: {}", out_trade_no);
      log.info("* 支付宝交易号: {}", trade_no);
      log.info("* 实付金额: {}", total_amount);
      log.info("***************************************************************");
    }
    return new JsonResult(OK, "支付成功");
  }
}
